<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>构造函数和原型</title>
</head>
<body>
    <!--
        构造方法和原型:
               构造方法中如果申明了方法, 那么使用构造方法创建的对象中的方法不是同一个, 也就是说
            每次用构造方法创建的对象中的方法都会为其开辟一个内存空间, 这样就会导致内存浪费

               构造函数原型 prototype 构造函数通过原型分配的函数是所有对象所共享的
            每一个构造函数都有一个prototype属性, 指向另外一个对象. 注意这个 prototype 就是一个对象
            这个对象的所有属性和方法, 都会被构造函数所拥有

            我们可以把那些不变的方法, 直接定义在 prototype 对象上, 这样所有对象的实例就可以共享这个方法了

            __proto__ 对象身上系统自己添加一个 __proto__ 指向我们构造函数的原型对象
     -->
<script>
    /* 原型对象的应用 扩展内置对象方法 */
    Array.prototype.sum = function () {
        let sum = 0
        for (let i = 0; i < this.length; i++) {
            sum += this[i]
            return sum
        }
    }

    /* 在 ES6 之前是没有继承概念的 一般是使用原型和构造函数实现 */
    // 1. 父构造函数
    function Father(uname, age) {
        // this 指向父类构造函数的对象实例
        this.uname = uname
        this.age = age
    }
    Father.prototype.money = function () {
        console.log(10000)
    }
    // 2. 子构造函数
    function Son(uname, age, score) {
        // this 指向子构造函数的对象实例
        Father.call(this, uname, age) // 调用父类的构造函数, 将子类的对象传入
        this.score = score
    }
    // Son.prototype = Father.prototype  这样直接赋值是错误的, 因为如果修改了子原型也会影响到父的原型对象
    Son.prototype = new Father() // 这才是正确的做法, 因为是实例对象所以子类影响不到父类原型的方法,
    // 如果利用对象的形式修改了原型对象, 别忘了利用constructor指回原来的构造函数
    Son.prototype.constructor = Son
    Son.prototype.exam = function() {
        console.log('exam')
    }

    let son = new Son('Jack', 18, 100)
    console.log(son)

</script>
</body>
</html>